package com.buaa.divinationmaster.comprehensive;

import android.content.Context;
import androidx.arch.core.executor.testing.InstantTaskExecutorRule;
import androidx.room.Room;
import androidx.test.core.app.ApplicationProvider;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;

import com.buaa.divinationmaster.core.database.DivinationDatabase;
import com.buaa.divinationmaster.core.database.entities.TarotCard;
import com.buaa.divinationmaster.feature.tarot.algorithm.TarotAlgorithmImpl;
import com.buaa.divinationmaster.feature.tarot.data.loader.TarotDataLoader;
import com.buaa.divinationmaster.feature.tarot.data.model.TarotSpread;
import com.buaa.divinationmaster.feature.tarot.data.model.TarotReading;
import com.buaa.divinationmaster.feature.tarot.data.repository.TarotRepository;
import com.buaa.divinationmaster.core.database.initializer.DatabaseInitializer;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import static org.junit.Assert.*;

import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * 综合测试套件
 * 验证整个塔罗系统的完整功能流程
 * by gaody
 */
@RunWith(RobolectricTestRunner.class)
@Config(sdk = 28)
public class ComprehensiveTestSuite {
    
    @Rule
    public InstantTaskExecutorRule instantTaskExecutorRule = new InstantTaskExecutorRule();
    
    private Context context;
    private DivinationDatabase database;
    private TarotRepository repository;
    private TarotAlgorithmImpl algorithm;
    private TarotDataLoader dataLoader;
    private DatabaseInitializer initializer;
    
    @Before
    public void setUp() {
        context = ApplicationProvider.getApplicationContext();
        database = Room.inMemoryDatabaseBuilder(context, DivinationDatabase.class)
                .allowMainThreadQueries()
                .build();
        
        repository = TarotRepository.getInstance(database);
        algorithm = new TarotAlgorithmImpl();
        dataLoader = new TarotDataLoader(context);
        initializer = DatabaseInitializer.getInstance(context);
    }
    
    @After
    public void tearDown() {
        if (database != null) {
            database.close();
        }
    }
    
    @Test
    public void testCompleteSystemIntegration() throws InterruptedException {
        // 1. 测试数据库初始化
        CountDownLatch initLatch = new CountDownLatch(1);
        final boolean[] initSuccess = {false};
        
        initializer.initializeDatabase(new DatabaseInitializer.InitializationCallback() {
            @Override
            public void onProgress(String phase, int current, int total) {
                System.out.println("初始化进度: " + phase + " (" + current + "/" + total + ")");
            }
            
            @Override
            public void onSuccess(String message) {
                initSuccess[0] = true;
                initLatch.countDown();
            }
            
            @Override
            public void onError(String error) {
                System.err.println("初始化失败: " + error);
                initLatch.countDown();
            }
        });
        
        assertTrue("数据库初始化应该在30秒内完成", initLatch.await(30, TimeUnit.SECONDS));
        assertTrue("数据库初始化应该成功", initSuccess[0]);
        
        // 2. 验证数据完整性
        assertTrue("数据应该已初始化", repository.isTarotDataInitialized());
        int cardCount = repository.getTarotCardCount();
        assertTrue("应该有塔罗牌数据", cardCount > 0);
        
        // 3. 测试算法功能
        List<TarotCard> allCards = repository.getAllCardsSync();
        assertNotNull("应该能获取所有卡牌", allCards);
        assertTrue("卡牌数量应该大于0", allCards.size() > 0);
        
        // 4. 测试完整占卜流程
        testCompleteDivinationFlow(allCards);
        
        // 5. 测试数据持久化
        testDataPersistence();
        
        // 6. 测试搜索功能
        testSearchFunctionality();
        
        System.out.println("✅ 所有综合测试通过");
    }
    
    private void testCompleteDivinationFlow(List<TarotCard> cards) {
        System.out.println("🔮 测试完整占卜流程...");
        
        // 创建占卜输入
        String question = "我的未来如何？";
        TarotSpread spread = TarotSpread.THREE_CARD;
        
        // 生成用户交互数据（模拟触摸）
        long[] touchTimes = {
            System.currentTimeMillis(),
            System.currentTimeMillis() + 100,
            System.currentTimeMillis() + 200
        };
        float[] touchX = {100f, 150f, 200f};
        float[] touchY = {200f, 250f, 300f};
        
        // 执行占卜算法
        TarotReading reading = algorithm.performReading(
            question, spread, touchTimes, touchX, touchY, cards
        );
        
        // 验证占卜结果
        assertNotNull("占卜结果不应该为空", reading);
        assertEquals("问题应该匹配", question, reading.getQuestion());
        assertEquals("牌阵应该匹配", spread, reading.getSpread());
        assertNotNull("应该有抽到的卡牌", reading.getDrawnCards());
        assertEquals("三张牌阵应该抽3张牌", 3, reading.getDrawnCards().size());
        assertNotNull("应该有解读", reading.getOverallInterpretation());
        assertTrue("应该是成功的占卜", reading.isSuccessful());
        
        System.out.println("占卜结果: " + reading.getOverallInterpretation());
    }
    
    private void testDataPersistence() throws InterruptedException {
        System.out.println("💾 测试数据持久化...");
        
        // 创建测试占卜结果
        String question = "测试持久化";
        TarotSpread spread = TarotSpread.SINGLE_CARD;
        List<TarotCard> cards = repository.getAllCardsSync();
        
        TarotReading reading = algorithm.performReading(
            question, spread,
            new long[]{System.currentTimeMillis()},
            new float[]{100f}, new float[]{200f},
            cards
        );
        
        // 保存占卜结果
        CountDownLatch saveLatch = new CountDownLatch(1);
        final boolean[] saveSuccess = {false};
        final long[] savedId = {0};
        
        repository.saveTarotReading(reading, new TarotRepository.SaveCallback() {
            @Override
            public void onSuccess(long id) {
                saveSuccess[0] = true;
                savedId[0] = id;
                saveLatch.countDown();
            }
            
            @Override
            public void onError(String error) {
                System.err.println("保存失败: " + error);
                saveLatch.countDown();
            }
        });
        
        assertTrue("保存应该在5秒内完成", saveLatch.await(5, TimeUnit.SECONDS));
        assertTrue("保存应该成功", saveSuccess[0]);
        assertTrue("应该获得有效ID", savedId[0] > 0);
        
        // 验证数据已保存
        int historyCount = database.divinationHistoryDao().getHistoryCount();
        assertTrue("历史记录数量应该大于0", historyCount > 0);
    }
    
    private void testSearchFunctionality() {
        System.out.println("🔍 测试搜索功能...");
        
        // 测试卡牌搜索
        List<TarotCard> searchResults = repository.searchCards("愚者");
        System.out.println("搜索'愚者'结果数量: " + searchResults.size());
        
        // 测试大阿卡纳查询
        List<TarotCard> majorCards = repository.getMajorArcana();
        assertNotNull("大阿卡纳列表不应该为空", majorCards);
        System.out.println("大阿卡纳数量: " + majorCards.size());
        
        // 测试小阿卡纳查询
        List<TarotCard> minorCards = repository.getMinorArcana();
        assertNotNull("小阿卡纳列表不应该为空", minorCards);
        System.out.println("小阿卡纳数量: " + minorCards.size());
        
        // 测试按花色查询
        if (!minorCards.isEmpty()) {
            String firstSuit = minorCards.get(0).getSuit();
            if (firstSuit != null) {
                List<TarotCard> suitCards = repository.getMinorArcanaBySuit(firstSuit);
                assertNotNull("花色卡牌列表不应该为空", suitCards);
                System.out.println(firstSuit + "花色数量: " + suitCards.size());
            }
        }
    }
    
    @Test
    public void testAlgorithmStability() {
        System.out.println("🧮 测试算法稳定性...");
        
        List<TarotCard> cards = createMinimalTestDeck();
        
        // 执行多次占卜，验证结果的一致性和随机性
        String question = "稳定性测试";
        TarotSpread spread = TarotSpread.THREE_CARD;
        
        int iterations = 10;
        int successCount = 0;
        
        for (int i = 0; i < iterations; i++) {
            long[] touchTimes = {
                System.currentTimeMillis() + i * 100,
                System.currentTimeMillis() + i * 100 + 50,
                System.currentTimeMillis() + i * 100 + 100
            };
            float[] touchX = {100f + i, 150f + i, 200f + i};
            float[] touchY = {200f + i, 250f + i, 300f + i};
            
            TarotReading reading = algorithm.performReading(
                question, spread, touchTimes, touchX, touchY, cards
            );
            
            if (reading != null && reading.isSuccessful()) {
                successCount++;
            }
        }
        
        assertTrue("至少80%的占卜应该成功", successCount >= iterations * 0.8);
        System.out.println("稳定性测试: " + successCount + "/" + iterations + " 成功");
    }
    
    @Test
    public void testErrorHandling() {
        System.out.println("❌ 测试错误处理...");
        
        // 测试空参数处理
        TarotReading result1 = algorithm.performReading(
            null, TarotSpread.SINGLE_CARD, 
            new long[]{System.currentTimeMillis()}, 
            new float[]{100f}, new float[]{200f}, 
            createMinimalTestDeck()
        );
        assertNull("空问题应该返回null", result1);
        
        // 测试空牌组处理
        TarotReading result2 = algorithm.performReading(
            "测试问题", TarotSpread.SINGLE_CARD,
            new long[]{System.currentTimeMillis()},
            new float[]{100f}, new float[]{200f},
            null
        );
        assertNull("空牌组应该返回null", result2);
        
        // 测试不匹配的数组长度
        TarotReading result3 = algorithm.performReading(
            "测试问题", TarotSpread.THREE_CARD,
            new long[]{System.currentTimeMillis()}, // 1个元素
            new float[]{100f}, new float[]{200f}, // 1个元素
            createMinimalTestDeck()
        );
        assertNull("数组长度不匹配应该返回null", result3);
        
        System.out.println("错误处理测试通过");
    }
    
    @Test
    public void testPerformanceBaseline() {
        System.out.println("⚡ 测试性能基准...");
        
        List<TarotCard> cards = createMinimalTestDeck();
        String question = "性能测试";
        TarotSpread spread = TarotSpread.SINGLE_CARD;
        
        long startTime = System.currentTimeMillis();
        int iterations = 100;
        
        for (int i = 0; i < iterations; i++) {
            algorithm.performReading(
                question, spread,
                new long[]{System.currentTimeMillis()},
                new float[]{100f}, new float[]{200f},
                cards
            );
        }
        
        long duration = System.currentTimeMillis() - startTime;
        double avgTime = (double) duration / iterations;
        
        System.out.println("性能基准: " + iterations + "次占卜耗时 " + duration + "ms");
        System.out.println("平均每次占卜: " + avgTime + "ms");
        
        assertTrue("单次占卜应该在100ms内完成", avgTime < 100);
    }
    
    // ========== 辅助方法 ==========
    
    private List<TarotCard> createMinimalTestDeck() {
        List<TarotCard> cards = repository.getAllCardsSync();
        if (cards.isEmpty()) {
            // 如果没有数据，创建最小测试牌组
            cards = java.util.Arrays.asList(
                createTestCard(0, "愚者", "The Fool", "major"),
                createTestCard(1, "魔术师", "The Magician", "major"),
                createTestCard(2, "女祭司", "The High Priestess", "major")
            );
        }
        return cards;
    }
    
    private TarotCard createTestCard(int id, String nameZh, String nameEn, String type) {
        TarotCard card = new TarotCard();
        card.setId(id);
        card.setNameZh(nameZh);
        card.setNameEn(nameEn);
        card.setType(type);
        card.setUprightMeaning("正位含义");
        card.setReversedMeaning("逆位含义");
        card.setUprightKeywords("关键词");
        card.setReversedKeywords("逆位关键词");
        return card;
    }
}
